package com.vchello.util;

import java.io.IOException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.vchello.contants.CONTANTS;
import com.vchello.contants.SmsCode;

import net.sf.json.JsonConfig;
import net.sf.json.util.PropertyFilter;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * 类功能描述：工具类
 * 
 */
public class Utility {
	private static Logger logger = Logger.getLogger(CONTANTS.class);
	public static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	public static SimpleDateFormat format2 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
	private final static String DES = "DES";
	private final static String KEY = "vchello_20160405";

	/**
	 * 在进行json转换时,将javabean对象中的属性过滤掉,如级联对象
	 * @param propArray
	 * @return
	 * @author:
	 */
	public static JsonConfig excludeJsonProperty(String[] propArray) {
		JsonConfig config = new JsonConfig();
		final String[] array = propArray;
		config.setJsonPropertyFilter(new PropertyFilter() {

			public boolean apply(Object source, String name, Object value) {
				for (String propName : array) {
					if (name.equals(propName)) {
						return true;
					}
				}
				return false;
			}
		});
		return config;
	}

	/**
	 * yyyyMMdd
	 * @return
	 */
	public static String getDateNow() {
		SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
		String date = format.format(new Date());
		return date;
	}

	/**
	 * @return
	 */
	public static String getDateNowFromformatStr(String formatStr) {
		SimpleDateFormat format = new SimpleDateFormat(formatStr);
		String date = format.format(new Date());
		return date;
	}
	
	/**
	 * 时间转制定字符串
	 * @param date
	 * @param dateFormat
	 * @return
	 */
	public static String getSimpleFormatedByDate(Date date, String dateFormat) {
		SimpleDateFormat format = new SimpleDateFormat(dateFormat);
		String retDate = format.format(date);
		return retDate;
	}
	
	/**
	 * yyyyMMdd 一周内 开始时间 and 结束时间 周一开始周日结束
	 * @return
	 */
	public static String[] getDateWeekNow() {
		String time[] = new String[2];
		SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
		int week = Integer.parseInt(getWeek());
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.DATE, -week + 1);
		time[0] = format.format(cal.getTime());
		cal.add(Calendar.DATE, 7);
		time[1] = format.format(cal.getTime());
		return time;

	}

	/**
	 * yyyy-MM-dd hh24:mm:ss
	 * @return
	 */
	public static String getSimpleFormatedDayNow() {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String date = format.format(new Date());
		return date;
	}

	/**
	 * 在进行json转换时,把需要的属性设置到json中
	 * @param propArray
	 * @return
	 * @author:
	 */
	public static JsonConfig includeJsonProperty(String[] propArray) {
		JsonConfig config = new JsonConfig();
		final String[] array = propArray;
		config.setJsonPropertyFilter(new PropertyFilter() {

			public boolean apply(Object source, String name, Object value) {
				for (String propName : array) {
					if (name.equals(propName)) {
						return false;
					}
				}
				return true;
			}
		});
		return config;
	}

	public static String md5md5(String source) {
		return md5(md5(source));
	}

	public static String md5(String source) {
		StringBuffer sb = new StringBuffer(32);
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			byte[] array = md.digest(source.getBytes("utf-8"));
			for (int i = 0; i < array.length; i++) {
				sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).toUpperCase().substring(1, 3));
			}
		} catch (Exception e) {
			logger.error("Can not encode the string '" + source + "' to MD5!", e);
			return null;
		}

		return sb.toString();
	}

	private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
			'e', 'f' };

	/**
	 * Takes the raw bytes from the digest and formats them correct.
	 * @param bytes
	 *            the raw bytes from the digest.
	 * @return the formatted bytes.
	 */
	private static String getFormattedText(byte[] bytes) {
		int len = bytes.length;
		StringBuilder buf = new StringBuilder(len * 2);
		// 把密文转换成十六进制的字符串形式
		for (int j = 0; j < len; j++) {
			buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
			buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
		}
		return buf.toString();
	}

	/**
	 * sha1加密
	 * 
	 * @param source
	 * @return
	 */
	public static String sha1(String source) {
		try {
			if (source == null) {
				return null;
			}
			try {
				MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
				messageDigest.update(source.getBytes());
				return getFormattedText(messageDigest.digest());
			} catch (Exception e) {
				throw new RuntimeException(e);
			}

		} catch (Exception e) {
			logger.error("Can not encode the string '" + source + "' to SHA1!", e);
			return null;
		}
	}

	/*
	 * 判断是否为浮点数，包括double和float
	 * @param str 传入的字符串
	 * @return 是浮点数返回true,否则返回false
	 */
	public static boolean isDouble(String str) {
		Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$");
		return pattern.matcher(str).matches();
	}

	/**
	 * 获取前一天
	 */
	public static String getBeforeDay() {
		Calendar cal = Calendar.getInstance();
		long time = new Date().getTime() - 24 * 60 * 60 * 1000;
		cal.setTimeInMillis(time);
		SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
		String date = format.format(cal.getTime());
		return date;
	}

	/**
	 * 1~7 星期一~七 获取星期
	 */
	public static String getWeek() {
		Calendar cal = Calendar.getInstance();
		int week = cal.get(Calendar.DAY_OF_WEEK) - 1;
		if (week == 0)
			week = 7;
		return "" + week;
	}

	/**
	 * 判断文件类型
	 * 
	 * @param logoPicContentType
	 * @return
	 */
	public static boolean checkPic(String logoPicContentType) {
		int index = logoPicContentType.lastIndexOf(".");
		if (index == -1)
			return false;
		String type = logoPicContentType.substring(index + 1, logoPicContentType.length());
		for (int i = 0; i < CONTANTS.PIC_TYPES.length; i++) {
			if (CONTANTS.PIC_TYPES[i].equals(type.toLowerCase())) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * 判断文件类型
	 * 
	 * @param logoPicContentType
	 * @return
	 */
	public static boolean checkFile(String logoPicContentType) {
		int index = logoPicContentType.lastIndexOf(".");
		if (index == -1)
			return false;
		String type = logoPicContentType.substring(index + 1, logoPicContentType.length());
		for (int i = 0; i < CONTANTS.FILE_TYPES.length; i++) {
			if (CONTANTS.FILE_TYPES[i].equals(type.toLowerCase())) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 普通电话验证
	 * 
	 * @param phone
	 * @return
	 */
	public static boolean checkTelphone(String phone) {
		String check = "1([\\d]{10})|((\\+[0-9]{2,4})?\\(?[0-9]+\\)?-?)?[0-9]{7,8}";
		boolean flag = false;
		try {
			Pattern p = Pattern.compile(check);
			Matcher m = p.matcher(phone);
			flag = m.matches();
		} catch (Exception e) {
			flag = false;
		}
		return flag;
	}

	/**
	 * 手机号码验证
	 * 
	 * @param mobiles
	 * @return
	 */
	public static boolean isMobileNO(String mobiles) {
		boolean flag = false;
		try {
			// 13********* ,15********,18*********,17*********
			Pattern p = Pattern.compile("^((17[0-9])|(13[0-9])|(15[^4,\\D])|(18[0-9]))\\d{8}$");
			Matcher m = p.matcher(mobiles);
			flag = m.matches();
		} catch (Exception e) {
			flag = false;
		}
		return flag;
	}

	/**
	 * 验证邮箱
	 * 
	 * @param email
	 * @return
	 */
	public static boolean checkEmail(String email) {
		String check = "^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$";
		Pattern regex = Pattern.compile(check);
		if (regex.matcher(email).matches()) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 获得一个UUID
	 * 
	 * @return String UUID
	 */
	public static String getUUID() {
		String s = UUID.randomUUID().toString();
		// 去掉“-”符号
		return s.substring(0, 8) + s.substring(9, 13) + s.substring(14, 18) + s.substring(19, 23) + s.substring(24);
	}

	/**
	 * 获得一个getEndTime
	 * @return
	 * @throws ParseException
	 */
	public static String addDate(String date, int day) throws ParseException {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Calendar ca = Calendar.getInstance();
		ca.setTime(format.parse(date));
		ca.add(Calendar.DATE, day);// 30为增加的天数，可以改变的
		Date d = ca.getTime();
		return format.format(d);
	}
	
	/**
	 * 获得明天时间 yyyy-MM-dd
	 * @return
	 * @throws ParseException
	 */
	public static String getTomorrowDate(String date) throws ParseException {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		Calendar ca = Calendar.getInstance();
		ca.setTime(format.parse(date));
		ca.add(Calendar.DATE, 1);// 30为增加的天数，可以改变的
		Date d = ca.getTime();
		return format.format(d);
	}
	
	/**
	 * 本周开始时间 yyyy-MM-dd
	 * @return
	 */
	public static String getStartWeek(){
		Calendar cal =Calendar.getInstance();
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); //获取本周一的日期
		return df.format(cal.getTime());
	}
	
	/**
	 * 本周结束时间 yyyy-MM-dd
	 * @return
	 */
	public static String getEndWeek(){
		Calendar cal =Calendar.getInstance();
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY); //获取本周一的日期
		cal.add(Calendar.WEEK_OF_YEAR, 1);
		return df.format(cal.getTime());
	}
	
	/**
	 * 获取本周六时间 yyyy-MM-dd
	 */
	public static String getSaturday(){
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		LocalDate localDate = LocalDate.parse(df.format(new Date()));
		LocalDate nextSunday = localDate.with(TemporalAdjusters.next(DayOfWeek.SATURDAY));
		return nextSunday.toString();
	}
	
	/**
	 * 获取本周日时间 yyyy-MM-dd
	 */
	public static String getSunday(){
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		LocalDate localDate = LocalDate.parse(df.format(new Date()));
		LocalDate nextSunday = localDate.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
		return nextSunday.toString();
	}
	
	/**
	 * 获取本月第一天时间 yyyy-MM-dd
	 */
	public static String getFirstDayOfMonth(){
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		LocalDate localDate = LocalDate.parse(df.format(new Date()));
		LocalDate nextSunday = localDate.with(TemporalAdjusters.firstDayOfMonth());
		return nextSunday.toString();
	}
	
	/**
	 * 获取本月最后一天时间 yyyy-MM-dd
	 */
	public static String getLastDayOfMonth(){
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		LocalDate localDate = LocalDate.parse(df.format(new Date()));
		LocalDate nextSunday = localDate.with(TemporalAdjusters.lastDayOfMonth());
		return nextSunday.toString();
	}
	
	/**
	 * 商业计划书格式
	 * @param bpFileName
	 * @return
	 */
	public static boolean checkBPFile(String bpFileName) {
		int index = bpFileName.lastIndexOf(".");
		if (index == -1)
			return false;
		String type = bpFileName.substring(index + 1, bpFileName.length());
		for (int i = 0; i < CONTANTS.BP_TYPES.length; i++) {
			if (CONTANTS.BP_TYPES[i].equals(type.toLowerCase())) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 获取天数
	 * 
	 * @param day
	 * @return
	 * @throws Exception
	 */
	public static int getDays(String day) throws Exception {
		if (day == null)
			return 0;
		SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date d = date.parse(day);
		long dayTime = d.getTime() - new Date().getTime();
		if (dayTime > 0)
			return (int) (dayTime / (1000 * 60 * 60 * 24)) + 1;
		else
			return 0;

	}

	// 判断是否是数字
	public static boolean isNumeric(String str) {
		try {
			Integer.parseInt(str);
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}

	/**
	 * 获取随机6位数
	 * 
	 * @return
	 */
	public static String getRandom(int length) {
		String randomStr = "";
		String[] s = new String[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g",
				"h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
		for (int i = 0; i < length; i++) {
			Random random = new Random();
			int n = random.nextInt(s.length);
			randomStr += s[n];
		}
		return randomStr;

	}

	/**
	 * 时间格式 yyyy-MM-dd
	 * @param startTime
	 * @return
	 */
	public static boolean checkTime(String startTime) {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		try {
			format.parse(startTime);
			return true;
		} catch (ParseException e) {
			e.printStackTrace();
			return false;
		}

	}

	/**
	 * 时间格式 yyyy-MM-dd 时间小于7天
	 * 
	 * @param startTime
	 * @return
	 */
	public static boolean checkTime(String createTime, int day) {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		try {
			String date = Utility.addDate(createTime, day);
			Date afdate = format.parse(date);
			if (afdate.before(new Date())) {
				return false;
			} else {
				return true;
			}
		} catch (ParseException e) {
			e.printStackTrace();
			return false;
		}

	}

	public static boolean checkUrl(String url) {
		String regex = "^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";
		Pattern patt = Pattern.compile(regex);
		Matcher matcher = patt.matcher(url);
		boolean isMatch = matcher.matches();
		if (isMatch) {
			return false;
		} else {
			return true;
		}
	}

	/**
	 * 获取ip
	 * @param request
	 * @return
	 */
	public static String getIp(HttpServletRequest request) {
		String ipFromNginx = getHeader(request, "X-Real-IP");
		// System.out.println("ipFromNginx:" + ipFromNginx);
		// System.out.println("getRemoteAddr:" + request.getRemoteAddr());
		return StringUtils.isEmpty(ipFromNginx) ? request.getRemoteAddr() : ipFromNginx;
	}

	/**
	 * 获取host
	 * 
	 * @param request
	 * @return
	 */
	public static String getHost(HttpServletRequest request) {
		String hostFromNginx = getHeader(request, "Host");
		// System.out.println("ipFromNginx:" + ipFromNginx);
		// System.out.println("getRemoteAddr:" + request.getRemoteAddr());
		String hosts = StringUtils.isEmpty(hostFromNginx) ? request.getServerName() : hostFromNginx;
		String host = hosts.split(":")[0];
		return host;
	}

	private static String getHeader(HttpServletRequest request, String headName) {
		String value = request.getHeader(headName);
		return !StringUtils.isBlank(value) && !"unknown".equalsIgnoreCase(value) ? value : "";
	}

	/**
	 * 返回的格式 20110725160412,0 1234567890100 响应时间为20110725160412，响应状态为0
	 * 表明那个成功提交到服务器；1234567890100为返回的msgid，这个工状态报告匹配时使用。
	 * 
	 * @param returnCode
	 * @return
	 */
	public static String getReturnCode(String returnCode) {
		String code = returnCode.split(",")[1].split("\n")[0];
		return SmsCode.getMessage(Integer.parseInt(code));
	}

	/**
	 * 加密
	 * 
	 * @param inStr
	 * @return
	 */
	public static String encrypt(String inStr) {
		// String s = new String(inStr);
		char[] a = inStr.toCharArray();
		for (int i = 0; i < a.length; i++) {
			a[i] = (char) (a[i] ^ 't');
		}
		String s = new String(a);
		return s;
	}

	/**
	 * 解密
	 * 
	 * @param inStr
	 * @return
	 * @throws Exception 
	 */
	public static String decryption(String inStr) {
		char[] a = inStr.toCharArray();
		for (int i = 0; i < a.length; i++) {
			a[i] = (char) (a[i] ^ 't');
		}
		String k = new String(a);
		return k;
	}
	
	public static String encryptDes(String data) throws Exception {
		byte[] bt = encrypt(data.getBytes(), KEY.getBytes());
		String strs = new BASE64Encoder().encode(bt);
		return strs;
	}

	/**
	 * Description 根据键值进行解密
	 * 
	 * @param data
	 *            加密键byte数组
	 * @return
	 * @throws IOException
	 * @throws Exception
	 */
	public static String decryptDes(String data) throws IOException, Exception {
		if (data == null){
			return null;
		}
		BASE64Decoder decoder = new BASE64Decoder();
		byte[] buf = decoder.decodeBuffer(data);
		byte[] bt = decrypt(buf, KEY.getBytes());
		return new String(bt);
	}

	/**
	 * Description 根据键值进行加密
	 * 
	 * @param data
	 * @param key
	 *            加密键byte数组
	 * @return
	 * @throws Exception
	 */
	private static byte[] encrypt(byte[] data, byte[] key) throws Exception {
		// 生成一个可信任的随机数源
		SecureRandom sr = new SecureRandom();

		// 从原始密钥数据创建DESKeySpec对象
		DESKeySpec dks = new DESKeySpec(key);

		// 创建一个密钥工厂，然后用它把DESKeySpec转换成SecretKey对象
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
		SecretKey securekey = keyFactory.generateSecret(dks);

		// Cipher对象实际完成加密操作
		Cipher cipher = Cipher.getInstance(DES);

		// 用密钥初始化Cipher对象
		cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);

		return cipher.doFinal(data);
	}

	/**
	 * Description 根据键值进行解密
	 * 
	 * @param data
	 * @param key
	 *            加密键byte数组
	 * @return
	 * @throws Exception
	 */
	private static byte[] decrypt(byte[] data, byte[] key) throws Exception {
		// 生成一个可信任的随机数源
		SecureRandom sr = new SecureRandom();
		// 从原始密钥数据创建DESKeySpec对象
		DESKeySpec dks = new DESKeySpec(key);
		// 创建一个密钥工厂，然后用它把DESKeySpec转换成SecretKey对象
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
		SecretKey securekey = keyFactory.generateSecret(dks);
		// Cipher对象实际完成解密操作
		Cipher cipher = Cipher.getInstance(DES);
		// 用密钥初始化Cipher对象
		cipher.init(Cipher.DECRYPT_MODE, securekey, sr);
		return cipher.doFinal(data);
	}
}
